package itext.test.example.finalItext;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

public class PdfReplacer {

	private static final Logger logger = LoggerFactory.getLogger(PdfReplacer.class);

	private int fontSize;
	
	//被替换的文字的绝对位置
	private Map<String, ReplaceRegion> replaceRegionMap = new HashMap<String, ReplaceRegion>();
	
	//需要被替换和被替换的文字信息
	private Map<String, Object> replaceTextMap = new HashMap<String, Object>();
	
	private ByteArrayOutputStream output;
	private PdfReader reader;
	private PdfStamper stamper;
	private List<PdfContentByte> canvas = new ArrayList<PdfContentByte>();
	// private PdfContentByte canvas ;
	private Font font;

	public PdfReplacer(byte[] pdfBytes) throws DocumentException, IOException {
		init(pdfBytes);
	}

	public PdfReplacer(String fileName) throws IOException, DocumentException {
		FileInputStream in = null;
		try {
			in = new FileInputStream(fileName);
			// available()，读写操作前先得知数据流里有多少个字节
			byte[] pdfBytes = new byte[in.available()];
			in.read(pdfBytes);
			init(pdfBytes);
		} finally {
			in.close();
		}
	}

	private void init(byte[] pdfBytes) throws DocumentException, IOException {
		logger.info("初始化开始");
		reader = new PdfReader(pdfBytes);
		output = new ByteArrayOutputStream();
		stamper = new PdfStamper(reader, output);

		System.out.println("导入的pdf共：" + reader.getNumberOfPages() + "页！");

		for (int i = 0; i < reader.getNumberOfPages(); i++) {
			PdfContentByte canva = stamper.getOverContent(i + 1);
			canvas.add(canva);
		}

		// 设置字体大小
		setFont(10);
		logger.info("初始化成功");
	}

	private void close() throws DocumentException, IOException {
		if (reader != null) {
			reader.close();
		}
		if (output != null) {
			output.close();
		}

		output = null;
		replaceRegionMap = null;
		replaceTextMap = null;
	}

	public void replaceText(float x, float y, float w, float h, String text) {
		ReplaceRegion region = new ReplaceRegion(text); // 用文本作为别名
		region.setH(h);
		region.setW(w);
		region.setX(x);
		region.setY(y);
		addReplaceRegion(region);
		this.replaceText(text, text);
	}

	public void replaceText(String name, String text) {
		this.replaceTextMap.put(name, text);
	}

	/**
	 * 替换文本
	 * 
	 * @throws IOException
	 * @throws DocumentException
	 */
	private void process() throws DocumentException, IOException {
		try {
			
			for (int i = 0 ; i < this.canvas.size() ; i++) {
				
				PdfContentByte canva = canvas.get(i);
			
				//解析需要替换的文本,参数为页码，从1开始，被替换的文字的位置信息
				parseReplaceText(i+1);
				
				canva.saveState();
				Set<Entry<String, ReplaceRegion>> entrys = this.replaceRegionMap.entrySet();
				
				//根据得到的被替换文字的位置信息，开始覆盖这些区域
				for (Entry<String, ReplaceRegion> entry : entrys) {
					ReplaceRegion value = entry.getValue();
					canva.setColorFill(BaseColor.WHITE);
					canva.rectangle(value.getX(), value.getY(), value.getW(), value.getH());
				}
				canva.fill();
				canva.restoreState();
				// 开始写入要被替换的文本在这些区域
				canva.beginText();
				for (Entry<String, ReplaceRegion> entry : entrys) {
					ReplaceRegion value = entry.getValue();
					// 设置字体
					canva.setFontAndSize(font.getBaseFont(), getFontSize());
					canva.setTextMatrix(value.getX(), value.getY() + 2/* 修正背景与文本的相对位置 */);
					canva.showText((String) replaceTextMap.get(value.getAliasName()));
				}
				canva.endText();
				//如PDF为多页，则清空之前的文本位置信息，下一页查找结果继续存储至map中
				this.replaceRegionMap.clear();
			}
		} finally {
			if (stamper != null) {
				stamper.close();
			}
		}
	}

	/**
	 * 未指定具体的替换位置时，系统自动查找位置
	 */
	private void parseReplaceText(int pageNum) {
		//pdf位置解析类
		PdfPositionParse parse = new PdfPositionParse(reader);
		
		Set<Entry<String, Object>> entrys = this.replaceTextMap.entrySet();
		
		//将需要被替换的的文本信息，作为key,传递给parse
		for (Entry<String, Object> entry : entrys) {
			//此时被替换文本的位置信息Map仍然为空----------------
			if (this.replaceRegionMap.get(entry.getKey()) == null) {
				//将被查找的内容传递给parse中的FindText map中
				parse.addFindText(entry.getKey());
			}
		}

		try {
			//解析指定的页面，获取要替换的文字的位置信息
			Map<String, ReplaceRegion> parseResult = parse.parse(pageNum);
//			this.replaceRegionMap = parse.parse(pageNum);
			Set<Entry<String, ReplaceRegion>> parseEntrys = parseResult.entrySet();
			for (Entry<String, ReplaceRegion> entry : parseEntrys) {
				//可能存在某些被替换的文本未被找到，此时位置信息为空
				if (entry.getValue() != null) {
					//将解析获取的数据，存放在本类的replaceRegionMap中
					this.replaceRegionMap.put(entry.getKey(), entry.getValue());
				}
			}
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}

	}

	/**
	 * 生成新的PDF文件
	 * 
	 * @param fileName
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void toPdf(String fileName) throws DocumentException, IOException {
		FileOutputStream fileOutputStream = null;
		try {
			process();
			fileOutputStream = new FileOutputStream(fileName);
			fileOutputStream.write(output.toByteArray());
			fileOutputStream.flush();
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
			throw e;
		} finally {
			if (fileOutputStream != null) {
				fileOutputStream.close();
			}
			close();
		}
		logger.info("文件生成成功");
	}

	/**
	 * 将生成的PDF文件转换成二进制数组
	 * 
	 * @return
	 * @throws DocumentException
	 * @throws IOException
	 */
	public byte[] toBytes() throws DocumentException, IOException {
		try {
			process();
			logger.info("二进制数据生成成功");
			return output.toByteArray();
		} finally {
			close();
		}
	}

	/**
	 * 添加替换区域
	 * 
	 * @param replaceRegion
	 */
	public void addReplaceRegion(ReplaceRegion replaceRegion) {
		this.replaceRegionMap.put(replaceRegion.getAliasName(), replaceRegion);
	}

	/**
	 * 通过别名得到替换区域
	 * 
	 * @param aliasName
	 * @return
	 */
	public ReplaceRegion getReplaceRegion(String aliasName) {
		return this.replaceRegionMap.get(aliasName);
	}

	public int getFontSize() {
		return fontSize;
	}

	/**
	 * 设置字体大小
	 * 
	 * @param fontSize
	 * @throws DocumentException
	 * @throws IOException
	 */
	public void setFont(int fontSize) throws DocumentException, IOException {
		if (fontSize != this.fontSize) {
			this.fontSize = fontSize;
			BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
			font = new Font(bf, this.fontSize, Font.BOLD);
		}
	}

	public void setFont(Font font) {
		if (font == null) {
			throw new NullPointerException("font is null");
		}
		this.font = font;
	}

	public static void main(String[] args) throws IOException, DocumentException {
		//实例化本类，然后读取源文件，并初始化成功
		PdfReplacer textReplacer = new PdfReplacer("d:/2.pdf");
		//将需要替换的文本，加入到 replaceTextMap 中
		textReplacer.replaceText("2018-11-16", "2020-11-13");
		textReplacer.replaceText("2018-11-17", "2020-11-14");
		textReplacer.replaceText("行政大床房", "大床");
		textReplacer.replaceText("大床", "超大床");
		textReplacer.replaceText("含双早", "  ");
		textReplacer.replaceText("1", "3");
		textReplacer.replaceText("JIE/LIJUN", "王沛");
		textReplacer.replaceText("北京明日五洲酒店", "香格里拉大酒店");
		textReplacer.replaceText("如订单首晚未到店或延迟入住，请务必提前联系酒店(也可通过为您预订酒店的旅行社或代理联系", "1111111111111111111111111111111111111111111222222222222222222222222223333444455566677777777777777778999123456789");
		
		// textReplacer.replaceText("9045", "8888");
		//生成需要的pdf
		textReplacer.toPdf("d:/test1.pdf");
	}
}
